﻿/* Write a method that return the maximal element in a portion of array of integers starting at given index. 
 * Using it write another method that sorts an array in ascending / descending order. */

using System;
using System.Collections.Generic;

class MaximalElement
{
    static void Main()
    {
        uint N;
        bool iProvided = false;

        //get array elements from user input
        do
        {
            if (iProvided == true) Console.WriteLine("Error! Please type a POSITIVE integer number.\r\nValid ranges: 1 - {0}", uint.MaxValue);
            else iProvided = true;
            Console.Write("Please provide how many elements you wish for the array to have: ");
        } while (UInt32.TryParse(Console.ReadLine(), out N) == false || N < 1);

        //allocate memory and assign values (source: user input)
        int[] nums = new int[N];

        for (int i = 0; i < N; i++)
        {
            //check if we have proper input values, if not send a request to the user to input again
            iProvided = false; //reset iProvided to avoid a "false positive" error
            do
            {
                if (iProvided == true) Console.WriteLine("Error! Please type an integer number.\r\nValid ranges: {1} - {0}", int.MaxValue, int.MinValue);
                else iProvided = true;
                Console.Write("Enter array element #{0}: ", i+1);
            } while (Int32.TryParse(Console.ReadLine(), out nums[i]) == false);
        }

        //get max element
        int startpos = 0;
        int max_e = getmaxel(nums, startpos);

        string optmsg = null;
        if (startpos > 0) if (startpos > 0) optmsg = string.Format(" (starting at position {0})", startpos);
        Console.WriteLine("Maximal element of the subset {0} is {1} {2}", string.Join(",", nums), max_e, optmsg);

        Console.WriteLine(
        @"
         The sorted array in ascending order is: {0}
         The sorted array in descending order is: {1}", string.Join(",", sortArray(nums)), string.Join(",", sortArray(nums, 1)));
    }

    /* method to sort an array
     parameters:
     nums - the one-dimensional array you want to sort
     type - 0, 1;
     0 for ascending, 1 for descending. default is ascending
     */
    private static int[] sortArray(int[] nums, int type = 0)
    {
        int[] nums_sorted = (int[])nums.Clone();

        int? max = null;
        for (int i = 0; i < nums.Length-1; i++)
        {
            int tmp = nums_sorted[i];
            max = getmaxel(nums_sorted, i);
            nums_sorted[i] = (int)max;

            int maxI = Array.IndexOf(nums_sorted, max, i+1);
            if (maxI > 0 && maxI < nums.Length) nums_sorted[maxI] = tmp;
        }

        //ascending order
        if (type == 0)
        {
            Array.Reverse(nums_sorted); //I'm too lazy to write this on my own.. deadlines are too close and so
            return nums_sorted;
        }

        //descending order
        return nums_sorted;
    }

    /* method to get the maximal elements in an array by starting at given index 
     parameters: int[] nums - the array we want to search in
     start: the index we want to start at
     */
    private static int getmaxel(int[] nums, int start = 0)
    {
        if (start > nums.Length-1) throw new IndexOutOfRangeException(); //throw an error on invalid argument
        
        int max = int.MinValue;
        for (int i = start; i < nums.Length; i++)
        {
            if (nums[i] > max) max = nums[i];
        }
        return max;
    }
}
